home *** CD-ROM | disk | FTP | other *** search
- /* Original Header from BBC BASIC version.
-
- This program will unpack Spark or arc style archives on the BBC
- and Archimedes. To produce an archive that can be unpacked using it
- you must set arc or Spark to not use squashing.
- Although you can use this on the Archie, a much better solution,
- is to use !SparkPlug. If you have an Archie, and would like to make
- your own archives and manipulate them in style from the desktop,
- you need a copy of Spark. This is obtainable for M-#5.99 from:
- David Pilling,
- P.O. Box 22,
- Thornton Cleveleys,
- Blackpool.
- FY5 1LR.
-
- You are encouraged to add your own bits to this program and pass it on.
- If you do modify it, add your name and details below.
-
- V0.00 20th September 1989 -- David Pilling
- V0.01 25th September 1989 -- Philip Colmer
- Changed BASIC V usage to BASIC II
- V0.02 21st February 1990 -- Philip Colmer
- Improved support for DFS
- V0.03 22nd April 1991 -- Philip Colmer
- Fixed bugs in directory handling
-
-
- This version, renamed Cark (for want of a better name !) is a port
- of Bark to Unix C. You are GREATLY encouraged to improve it...
- my knowledge of C is very limited and I suspect that the coding
- could be much better ! - Alun.
-
-
- V0.01 4th June 1991 -- Alun Jones
- Ported (messily!) to Unix style C.
-
- V0.02 2nd Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
- Further porting to 4.2BSD (and provision made
- for System V). Define either 'BSD' or 'SYSV'
- when compiling.
-
- V0.03 17th Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
- Fixed errors in function prototypes for PCC
- C compilers.
-
- V0.04 20th Dec 1991 -- Andy Duplain (duplain@rtf.bt.co.uk)
- Changed '-t' option output from stderr to stdout.
-
- V0.05 8th Jan 1992 -- Andy Duplain (duplain@rtf.bt.co.uk)
- Added patch posted to NEWS by Martin Percival
- (martin@thed.uk22.bull.com) to unpack type 127 archives.
- */
-
- #include <stdio.h>
-
- #ifdef BSD /* Berkeley */
- # include <strings.h>
- # define remove unlink
- # define UNIX
- # undef SYSV
- #endif
-
- #ifdef SYSV /* System V */
- # include <sys/types.h>
- # include <sys/stat.h>
- # include <string.h>
- # include <stdlib.h>
- # define remove unlink
- # define UNIX
- # undef BSD
- #endif
-
- #ifndef UNIX /* Not UNIX */
- # include <string.h>
- # include <stdlib.h>
- #endif
-
- #define MAXCODE(n) ((1<<n)-1)
-
- /* Used by many functions */
- static FILE * fp,
- *fo,
- *logfile;
- static char rmask[9] = {
- 0, 1, 3, 7, 15, 31, 63, 127, 255
- };
-
- static int buf[128];
- static char filename[255];
- char compname[270]; /* Ready for system() uncompress call */
- static int isdir,
- earc;
- static int run,
- c,
- rc;
-
- /* permissions of files, lengths, etc. */
- static long load,
- exec,
- attr,
- type,
- clen,
- olen;
- static int date,
- time,
- crc;
-
- /* Used by uncrunch/getcode */
- static int n_bits,
- clear_flg,
- maxcode,
- free_ent,
- offset,
- size;
-
- int testonly = 0; /* Used by -t option */
-
- /* Used to guard function prototypes for PCC and ANSI compilers... */
-
- #if defined(__STDC__) || defined(__cplusplus)
- # define P_(s) s
- #else
- # define P_(s) ()
- #endif
-
- int main P_((int argc, char **argv));
- int rdhdr P_((void));
- long word P_((void));
- int dble P_((void));
- void unpack P_((char *root, char *file));
- void unstore P_((void));
- void unpck P_((void));
- void putc_ncr P_((int b));
- int get_c P_((void));
- void uncrunch P_((void));
- int getcode P_((void));
-
- #undef P_
-
- int main (argc, argv)
- int argc;
- char **argv;
- {
- char cline[256],
- fullname[256];
- int level = 0;
- int l[32];
- l[0] = 0;
- *fullname = 0;
-
- /* Wrong # args */
- if (argc < 2) {
- fprintf (stderr, "Usage : %s [-t] <filename>\n", *argv);
- exit (1);
- }
-
- /* Crappy option parsing... */
-
- if (argc == 3 && argv[1][0] == '-')
- {
- switch(argv[1][1])
- {
- case 't': /* Test */
- testonly++;
- break;
- default:
- fprintf(stderr, "Unknown option '-%c'\n", argv[1][1]);
- exit(1);
- }
- *++argv;
- }
-
- /* Can't open file for reading */
- if ((fp = fopen (*++argv, "r")) == NULL) {
- fprintf (stderr, "\nCan't find file %s\n", *argv);
- exit (1);
- }
-
- /* Version number */
- puts("Cark V0.05 January 1992, based on Bark V0.03");
-
- /* File types */
- if (!testonly)
- logfile = fopen ("settypes", "w");
-
- /* Main loop - rdhdr returns non-zero if EOF reached */
- while (!rdhdr ()) {
- /* End of top level dir */
- if ((earc) && (level == 0))
- break;
-
- /* New directory in archive */
- if (isdir) {
- l[level++] = strlen(fullname);/* Remember old pathname */
- strcat(fullname, filename);/* Add new name */
- if (!testonly)
- {
- printf("Creating directory %s\n", fullname);
- #ifdef UNIX
- mkdir(fullname, 0755); /* Ignore error */
- #else /* Not UNIX */
- sprintf (cline, "mkdir %s\n", fullname);
- system (cline);
- #endif /* UNIX */
- }
- else
- printf("Directory %s\n", fullname);
- strcat (fullname, "/");/* Add the dir. separator */
- }
- else
- if (earc) {
- fullname[l[--level]] = 0;/* Step back up a level */
- if (strlen (fullname) != 0)
- printf ("Directory: %s\n", fullname);
- }
- else {
- if (testonly)
- printf ("Testing file : %s%s ... ", fullname, filename);
- else
- printf ("Restoring file : %s%s ... ", fullname, filename);
- unpack (fullname, filename);/* Not a dir, so a file */
- }
- }
- /* End of archive, so close files */
- fclose (fp);
- if (!testonly)
- fclose (logfile);
- exit (0);
- }
-
-
- /* Read header */
- int rdhdr () {
- int i;
-
- /* archive flag */
- if (getc (fp) != 26) { /* Missing flag, try and find another */
- fprintf (stderr, "Bad Header\n");
- while ((i = getc (fp)) != 26)
- if (i == EOF)
- break;
- if (i == EOF) {
- return (1);
- }
- }
-
- /* Compression type */
- type = getc (fp) & 0x7f;
-
- if (type == 0) { /* End of archive */
- earc = 1;
- isdir = 0;
- return (0);
- }
-
- earc = 0;
- for (i = 0; i <= 12; ++i) { /* Get filename */
- filename[i] = getc (fp);
- if (filename[i] <= 32)
- filename[i] = 0;
- }
-
- clen = word (); /* Compressed length */
- date = dble (); /* File creation date */
- time = dble (); /* File creation time */
- crc = dble (); /* crc byte - unchecked */
- if (type > 1)
- olen = word (); /* Compressed, so find original length */
- else
- olen = clen; /* Not compressed */
- load = word (); /* Load address */
- exec = word (); /* Execution address */
- attr = word (); /* File attributes */
- if ((type == 2) && ((load & 0xffffff00) == 0xfffddc00))
- isdir = 1; /* File is a directory */
- else
- isdir = 0; /* No it aint ! */
- return (0);
- }
-
-
- /* Get 4 bytes */
- long word () {
- long n;
- n = getc (fp);
- n |= (getc (fp) << 8);
- n |= (getc (fp) << 16);
- n |= (getc (fp) << 24);
- return (n);
- }
-
-
- /* Get 2 bytes */
- int dble () {
- int i;
- i = getc (fp);
- i |= (getc (fp) << 8);
- return (i);
- }
-
-
- /* Unpack file */
- void unpack (root, file)
- char *root,
- *file;
- {
- char fullpath[255];
- int i;
-
-
- /* Open file and report any error */
- sprintf (fullpath, "%s%s", root, file);
- if (!testonly && type != 127) /* type 127 uncompressed seperately */
- if ((fo = fopen (fullpath, "w")) == NULL) {
- fprintf (stderr, "Can't open file %s\n", fullpath);
- exit (1);
- }
-
- /* Decide appropriate compression action */
- switch (type) {
- case 1:
- case 2:
- /* Not compressed */
- unstore ();
- break;
- case 8:
- /* Crunched */
- uncrunch ();
- break;
- case 3:
- /* I dunno */
- unpck ();
- break;
- case 127: /* Compressed file, save as *.Z and use compress utility */
- if (testonly)
- puts("unix compress file");
- else
- puts("Uncompressing");
- strcpy(compname, "compress -d "); /* Perferable to uncompress */
- strcat(fullpath, ".Z");
- strcat(compname, fullpath);
- if (!testonly)
- {
- if ((fo = fopen(fullpath, "w")) == NULL)
- {
- fprintf(stderr, "Can't open file %s\n", fullpath);
- exit(1);
- }
-
- putc(31, fo); /* Write magic header for compress file */
- putc(157, fo);
- putc((getc(fp) + 0x80), fo); /* and adjust byte 1 of file to be UNIX
- bit indicator */
- while (clen-- > 1)
- putc(getc(fp), fo); /* Copy bytes (-1) */
-
- fclose(fo);
-
- if (system(compname)) /* Do the uncompress */
- {
- fprintf(stderr, "%s failed!\n", compname);
- exit(1);
- }
- }
- else /* Testing only */
- while(clen--)
- getc(fp); /* Throw away */
-
- break;
-
- default:
- {
- if (!testonly)
- fprintf (stderr, "Can't unpack %s - compression type %d\n", file, type);
- else
- printf("Can't unpack, compression type %d\n", type);
- /* Skip to end of file */
- for (i = 1; i <= clen; ++i)
- getc (fp);
- /* Remove output file */
- if (!testonly)
- remove (fullpath);
- }
- }
-
- if (!testonly && type != 127)
- fclose (fo);
- /* Save appropriate SYS "OS_File" call to set catalogue info */
- if (!testonly)
- {
- fprintf (logfile, "SYS %cOS_File%c, 1, %c", 34, 34, 34);
- for (i = 0; root[i] != 0; ++i)
- if (root[i] == '/')
- putc ('.', logfile);
- else
- putc (root[i], logfile);
- fprintf (logfile, "%s%c, &%x, &%x,, &%x\n", file, 34, load, exec, attr);
- }
- }
-
-
- /* No compression */
- void unstore () {
- int i;
- putchar('\n');
- for (i = 0; i < clen; ++i)
- if (testonly)
- getc(fp);
- else
- putc (getc (fp), fo);
- }
-
-
- /* Looks like run length of some sort to me */
- void unpck () {
- int i;
- run = 0;
- c = 0;
- if (testonly)
- putchar('\n');
- else
- puts("Unpacking");
- for (i = 0; i < clen; ++i)
- putc_ncr (getc (fp));
- }
-
-
- /* Dunno */
- void putc_ncr (b)
- int b;
- {
- int k;
-
- if (testonly)
- return;
-
- if (c == 1) {
- if (b == 0) {
- putc (0x90, fo);
- c = 0;
- return;
- }
- else {
- for (k = 1; k < b; ++k)
- putc (run, fo);
- c = 0;
- return;
- }
- }
- if (b == 0x90) {
- c = 1;
- return;
- }
- run = b;
- putc (run, fo);
- }
-
-
- int get_c () {
- if (rc > 0) {
- --rc;
- return (getc (fp));
- }
- else
- return (-1);
- }
-
-
- /* Crunched */
- void uncrunch () {
- int i,
- finchar,
- incode,
- code,
- oldcode;
- int stack[4096],
- *stackp;
- int suffix[4096];
- int prefix[4096];
-
- if (testonly)
- putchar('\n');
- else
- puts("Uncrunching");
-
- c = 0;
- offset = 0;
- size = 0;
- rc = clen;
- code = get_c ();
- if (code != 12) {
- fprintf (stderr, "Can't unpack file - wrong number of bits\n");
- exit (1);
- }
- n_bits = 9;
- clear_flg = 0;
- maxcode = MAXCODE (n_bits);
- for (i = 0; i <= 256; ++i)
- prefix[i] = 0;
- for (code = 0; code < 256; ++code)
- suffix[code] = code;
- free_ent = 257;
- oldcode = getcode ();
- finchar = oldcode;
- if (oldcode == -1)
- return;
- putc_ncr (finchar);
- stackp = stack;
-
- while (1) {
- code = getcode ();
- if (code < 0)
- return;
- if (code == 256) {
- for (i = 0; i <= 256; ++i)
- prefix[i] = 0;
- clear_flg = 1;
- free_ent = 256;
- code = getcode ();
- if (code == -1)
- return;
- }
- incode = code;
- if (code >= free_ent) {
- *stackp++ = finchar;
- code = oldcode;
- }
- while (code >= 256) {
- *stackp++ = suffix[code];
- code = prefix[code];
- }
- finchar = suffix[code];
- *stackp++ = finchar;
- while (stackp > stack)
- putc_ncr (*--stackp);
- code = free_ent;
- if (code < 4096) {
- prefix[code] = oldcode;
- suffix[code] = finchar;
- free_ent = code + 1;
- }
- oldcode = incode;
- }
- }
-
- int getcode () {
- int code,
- temp,
- r_off,
- bits;
- int bp = 0;
-
- if ((clear_flg > 0) || (offset >= size) || (free_ent > maxcode)) {
- if (free_ent > maxcode) {
- ++n_bits;
- if (n_bits == 12)
- maxcode = 4096;
- else
- maxcode = MAXCODE (n_bits);
- }
- if (clear_flg > 0) {
- n_bits = 9;
- maxcode = MAXCODE (n_bits);
- clear_flg = 0;
- }
- for (size = 0; size < n_bits; ++size) {
- code = get_c ();
- if (code == -1) {
- temp = size;
- size = n_bits;
- }
- else
- buf[size] = code;
- }
- if (size == (n_bits + 1)) {
- size = temp;
- if (size <= 0)
- return (-1);
- }
- offset = 0;
- size = (size << 3) - (n_bits - 1);
- }
- r_off = offset;
- bits = n_bits;
- bp += r_off >> 3;
- r_off = r_off & 7;
- code = buf[bp++] >> r_off;
- bits = bits - 8 + r_off;
- r_off = 8 - r_off;
- if (bits >= 8) {
- code = code | (buf[bp++] << r_off);
- r_off += 8;
- bits -= 8;
- }
- code = code | ((buf[bp] & rmask[bits]) << r_off);
- offset += n_bits;
- return (code & 4095);
- }
-